package ai

// countPieceInLine function
// 计算某个方向上的棋子个数
func countPieceInLine(board *TypeRepo[TypeRole], x, y, offsetX, offsetY int, role TypeRole) PieceCount {
	opponent := -role
	pieceCount := PieceCount{}
	tempEmptyCount := 0       // 临时变量
	for i := 1; i <= 5; i++ { //最多延伸5个位置
		nx, ny := x+i*offsetX, y+i*offsetY
		if nx < 0 || ny < 0 || nx >= board.size || ny >= board.size {
			break //超出边界
		}
		currentRole := board.Get(nx, ny)
		if currentRole == Chess.OBSTACLE || currentRole == opponent {
			break //遇到对方棋子或边界
		}
		if currentRole == role { //如果是role的棋子
			pieceCount.selfCount++
			pieceCount.sideEmptyCount = 0
			if tempEmptyCount > 0 {
				pieceCount.innerEmptyCount += tempEmptyCount
				tempEmptyCount = 0
			}
			if pieceCount.innerEmptyCount == 0 {
				pieceCount.noEmptySelfCount++
				pieceCount.oneEmptySelfCount++
			} else if pieceCount.innerEmptyCount == 1 {
				pieceCount.oneEmptySelfCount++
			}
		} else if currentRole == Chess.EMPTY {
			tempEmptyCount++
			pieceCount.sideEmptyCount++
		}
		if pieceCount.sideEmptyCount > 2 {
			break
		}
	}
	if pieceCount.innerEmptyCount == 0 {
		pieceCount.oneEmptySelfCount = 0
	}
	return pieceCount
}

// getShapeFast 使用遍历位置的方式实现的形状检测，速度较快，大约是字符串速度的2倍 但理解起来会稍微复杂一些
func getShapeFast(board *TypeRepo[TypeRole], x, y int, dire TypeDirection, role TypeRole) TypeShape {
	tCount := PieceCount{}
	offsetX, offsetY := DirectionVec[dire].x, DirectionVec[dire].y
	lCount := countPieceInLine(board, x, y, -offsetX, -offsetY, role)
	rCount := countPieceInLine(board, x, y, offsetX, offsetY, role)

	if board.Get(x, y) == role {
		tCount.selfCount = 1 + lCount.selfCount + rCount.selfCount
		tCount.noEmptySelfCount = 1 + lCount.noEmptySelfCount + rCount.noEmptySelfCount
		tCount.innerEmptyCount = lCount.innerEmptyCount + rCount.innerEmptyCount
		tCount.oneEmptySelfCount = 1 + max(lCount.noEmptySelfCount+rCount.oneEmptySelfCount, lCount.oneEmptySelfCount+rCount.noEmptySelfCount)
	} else if board.Get(x, y) == Chess.EMPTY {
		tCount.selfCount = lCount.selfCount + rCount.selfCount
		tCount.noEmptySelfCount = max(lCount.noEmptySelfCount, rCount.noEmptySelfCount)
		tCount.innerEmptyCount = 1 + lCount.innerEmptyCount + rCount.innerEmptyCount
		tCount.oneEmptySelfCount = lCount.noEmptySelfCount + rCount.noEmptySelfCount
		if lCount.selfCount == 0 && rCount.noEmptySelfCount > 0 {
			// 左边没有己方，但右边存在我方棋子，此时x,y位置设定为左侧空位
			lCount.sideEmptyCount++
		}
		if rCount.selfCount == 0 && lCount.noEmptySelfCount > 0 {
			// 右边没有己方，但左边存在我方棋子，此时x,y位置设定为右侧空位
			rCount.sideEmptyCount++
		}
	} else { //x,y点如果是对方棋子,只能以单边的最好结果为准
		//没有空位的情况：211111
		if lCount.noEmptySelfCount == 5 || rCount.noEmptySelfCount == 5 {
			return Shapes.FIVE
		}
		//一个空位的情况：211110|211011|210111|201111
		if lCount.selfCount == 4 || rCount.selfCount == 4 {
			return Shapes.BLOCK_FOUR
		}
		// 两个空位：211100|211010|210110|201110|211001|210101|210011|201101|201011|200111
		if (lCount.noEmptySelfCount == 3 && lCount.sideEmptyCount == 2) || (rCount.noEmptySelfCount == 3 && rCount.sideEmptyCount == 2) {
			// 211100
			return Shapes.BLOCK_THREE
		}
		if (lCount.oneEmptySelfCount == 3 && lCount.sideEmptyCount >= 1) || (rCount.oneEmptySelfCount == 3 && rCount.sideEmptyCount >= 1) {
			// 211010|210110|201110
			return Shapes.BLOCK_THREE
		}
		if (lCount.selfCount == 3 && lCount.innerEmptyCount == 2) || (rCount.selfCount == 3 && rCount.innerEmptyCount == 2) {
			// 211001|210101|210011|201101|201011|200111
			return Shapes.BLOCK_THREE
		}
		//三个空位
		if (lCount.selfCount == 2 && lCount.innerEmptyCount+lCount.sideEmptyCount >= 3) || (rCount.selfCount == 2 && rCount.innerEmptyCount+rCount.sideEmptyCount >= 3) {
			return Shapes.BLOCK_TWO
		}
		// 一个或者没有，不用太准确
		return Shapes.ONE
	}
	if tCount.noEmptySelfCount >= 5 {
		// 五连
		return Shapes.FIVE
	}
	if tCount.noEmptySelfCount == 4 && rCount.sideEmptyCount >= 1 && lCount.sideEmptyCount >= 1 {
		// 活四: 011110
		return Shapes.FOUR
	}
	if tCount.noEmptySelfCount == 4 && (rCount.sideEmptyCount >= 1 || lCount.sideEmptyCount >= 1) {
		// 冲四: 011112
		return Shapes.BLOCK_FOUR
	}
	if tCount.oneEmptySelfCount >= 4 {
		// 冲四: 10111 or 11011
		return Shapes.BLOCK_FOUR
	}
	if tCount.noEmptySelfCount == 3 && lCount.sideEmptyCount >= 1 && rCount.sideEmptyCount >= 1 && lCount.sideEmptyCount+rCount.sideEmptyCount >= 3 {
		// 活三: 001110
		return Shapes.THREE
	}
	if tCount.oneEmptySelfCount == 3 && rCount.sideEmptyCount >= 1 && lCount.sideEmptyCount >= 1 {
		// 活三：011010
		return Shapes.THREE
	}
	if tCount.noEmptySelfCount == 3 && rCount.sideEmptyCount+lCount.sideEmptyCount >= 2 {
		// 眠三: 211100|2011102
		return Shapes.BLOCK_THREE
	}
	if tCount.oneEmptySelfCount == 3 && (rCount.sideEmptyCount >= 1 || lCount.sideEmptyCount >= 1) {
		// 眠三: 211010|210110
		return Shapes.BLOCK_THREE
	}
	if tCount.selfCount == 3 && tCount.innerEmptyCount == 2 {
		// 眠三：11001|10101
		return Shapes.BLOCK_THREE
	}
	if tCount.noEmptySelfCount == 2 && lCount.sideEmptyCount >= 2 && rCount.sideEmptyCount >= 2 {
		// 活二：001100
		return Shapes.TWO
	}
	if tCount.oneEmptySelfCount == 2 && rCount.sideEmptyCount+lCount.sideEmptyCount >= 3 {
		// 活二：010100
		return Shapes.TWO
	}
	if tCount.selfCount == 2 && tCount.innerEmptyCount == 2 && rCount.sideEmptyCount >= 1 && lCount.sideEmptyCount >= 1 {
		// 活二：010010
		return Shapes.TWO
	}
	if tCount.noEmptySelfCount == 2 && rCount.sideEmptyCount+lCount.sideEmptyCount >= 3 {
		// TODO:这里其实不是很准确，因为单侧最多只查找2个空位，当xy位置是最边缘时这种情况会被忽略掉，不过眠二重要性比较低，所以就算漏了也影响不大
		//眠二：211000
		return Shapes.BLOCK_TWO
	}
	if tCount.oneEmptySelfCount == 2 && (rCount.sideEmptyCount >= 2 || lCount.sideEmptyCount >= 2) {
		// 眠二：210100
		return Shapes.BLOCK_TWO
	}
	if tCount.selfCount == 2 && (rCount.sideEmptyCount >= 1 || lCount.sideEmptyCount >= 1) && tCount.innerEmptyCount == 2 {
		// 眠二：210010
		return Shapes.BLOCK_TWO
	}
	if tCount.selfCount == 2 && tCount.innerEmptyCount == 3 {
		// 眠二：10001
		return Shapes.BLOCK_TWO
	}
	if tCount.selfCount >= 1 {
		return Shapes.ONE
	}
	return Shapes.NONE
}

// isFive function
func isFive(shape TypeShape) bool {
	return shape == Shapes.FIVE
}

// isFour function
func isFour(shape TypeShape) bool {
	return shape == Shapes.FOUR || shape == Shapes.BLOCK_FOUR
}

// getAllShapesOfPoint function
func getAllShapesOfPoint(shapeCache TypeShapeCache, x, y int, role TypeRole) []TypeShape {
	roles := []TypeRole{role}
	if role == Chess.EMPTY {
		roles = Roles
	}
	var result []TypeShape
	for _, r := range roles {
		for _, d := range DirectionEnum {
			shape := shapeCache[r][d].Get(x, y)
			if shape != Shapes.NONE {
				result = append(result, shape)
			}
		}
	}
	return result
}
